//! HTTP工具
//! 
//! 提供HTTP请求功能

use reqwest::blocking::{Client, Response};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use serde_json::Value;
use std::collections::HashMap;
use std::time::Duration;

/// HTTP错误类型
#[derive(Debug, thiserror::Error)]
pub enum HttpError {
    #[error("Request failed: {0}")]
    RequestFailed(#[from] reqwest::Error),
    #[error("Invalid URL: {0}")]
    InvalidUrl(String),
    #[error("Invalid header: {0}")]
    InvalidHeader(String),
    #[error("JSON parse error: {0}")]
    JsonError(#[from] serde_json::Error),
    #[error("HTTP error: {status}, body: {body}")]
    HttpError { status: u16, body: String },
}

pub type HttpResult<T> = Result<T, HttpError>;

/// HTTP客户端构建器
#[derive(Debug, Clone)]
pub struct HttpClient {
    client: Client,
    base_url: Option<String>,
    default_headers: HeaderMap,
    timeout: Duration,
}

impl Default for HttpClient {
    fn default() -> Self {
        Self::new()
    }
}

impl HttpClient {
    /// 创建新的HTTP客户端
    pub fn new() -> Self {
        let client = Client::builder()
            .timeout(Duration::from_secs(30))
            .build()
            .expect("Failed to create HTTP client");
        
        Self {
            client,
            base_url: None,
            default_headers: HeaderMap::new(),
            timeout: Duration::from_secs(30),
        }
    }
    
    /// 设置基础URL
    pub fn with_base_url(mut self, base_url: &str) -> Self {
        self.base_url = Some(base_url.to_string());
        self
    }
    
    /// 设置超时时间
    pub fn with_timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self.client = Client::builder()
            .timeout(timeout)
            .build()
            .expect("Failed to create HTTP client");
        self
    }
    
    /// 添加默认请求头
    pub fn with_header(mut self, key: &str, value: &str) -> HttpResult<Self> {
        let header_name = HeaderName::from_bytes(key.as_bytes())
            .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
        let header_value = HeaderValue::from_str(value)
            .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
        
        self.default_headers.insert(header_name, header_value);
        Ok(self)
    }
    
    /// 构建完整URL
    fn build_url(&self, path: &str) -> String {
        if let Some(ref base) = self.base_url {
            if path.starts_with("http://") || path.starts_with("https://") {
                path.to_string()
            } else {
                format!("{}/{}", base.trim_end_matches('/'), path.trim_start_matches('/'))
            }
        } else {
            path.to_string()
        }
    }
}

/// HTTP GET请求
/// 
/// # Examples
/// ```
/// use librarys::network::http_get;
/// 
/// let response = http_get("https://httpbin.org/get").unwrap();
/// println!("响应: {}", response);
/// ```
pub fn http_get(url: &str) -> HttpResult<String> {
    let client = HttpClient::new();
    client.get(url, None)
}

/// HTTP POST请求
/// 
/// # Examples
/// ```
/// use librarys::network::http_post;
/// 
/// let data = r#"{"key": "value"}"#;
/// let response = http_post("https://httpbin.org/post", data).unwrap();
/// println!("响应: {}", response);
/// ```
pub fn http_post(url: &str, data: &str) -> HttpResult<String> {
    let client = HttpClient::new();
    client.post(url, data, None)
}

impl HttpClient {
    /// GET请求
    pub fn get(&self, path: &str, headers: Option<HashMap<String, String>>) -> HttpResult<String> {
        let url = self.build_url(path);
        let mut request = self.client.get(&url);
        
        // 添加默认请求头
        request = request.headers(self.default_headers.clone());
        
        // 添加额外请求头
        if let Some(headers) = headers {
            for (key, value) in headers {
                let header_name = HeaderName::from_bytes(key.as_bytes())
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
                let header_value = HeaderValue::from_str(&value)
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
                request = request.header(header_name, header_value);
            }
        }
        
        let response = request.send()?;
        self.handle_response(response)
    }
    
    /// POST请求
    pub fn post(&self, path: &str, body: &str, headers: Option<HashMap<String, String>>) -> HttpResult<String> {
        let url = self.build_url(path);
        let mut request = self.client.post(&url);
        
        // 添加默认请求头
        request = request.headers(self.default_headers.clone());
        
        // 添加额外请求头
        if let Some(headers) = headers {
            for (key, value) in headers {
                let header_name = HeaderName::from_bytes(key.as_bytes())
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
                let header_value = HeaderValue::from_str(&value)
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
                request = request.header(header_name, header_value);
            }
        }
        
        let response = request.body(body.to_string()).send()?;
        self.handle_response(response)
    }
    
    /// POST JSON请求
    pub fn post_json(&self, path: &str, json: &Value, headers: Option<HashMap<String, String>>) -> HttpResult<String> {
        let url = self.build_url(path);
        let mut request = self.client.post(&url);
        
        // 添加默认请求头
        request = request.headers(self.default_headers.clone());
        
        // 添加Content-Type
        request = request.header("Content-Type", "application/json");
        
        // 添加额外请求头
        if let Some(headers) = headers {
            for (key, value) in headers {
                let header_name = HeaderName::from_bytes(key.as_bytes())
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
                let header_value = HeaderValue::from_str(&value)
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
                request = request.header(header_name, header_value);
            }
        }
        
        let response = request.json(json).send()?;
        self.handle_response(response)
    }
    
    /// PUT请求
    pub fn put(&self, path: &str, body: &str, headers: Option<HashMap<String, String>>) -> HttpResult<String> {
        let url = self.build_url(path);
        let mut request = self.client.put(&url);
        
        request = request.headers(self.default_headers.clone());
        
        if let Some(headers) = headers {
            for (key, value) in headers {
                let header_name = HeaderName::from_bytes(key.as_bytes())
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
                let header_value = HeaderValue::from_str(&value)
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
                request = request.header(header_name, header_value);
            }
        }
        
        let response = request.body(body.to_string()).send()?;
        self.handle_response(response)
    }
    
    /// DELETE请求
    pub fn delete(&self, path: &str, headers: Option<HashMap<String, String>>) -> HttpResult<String> {
        let url = self.build_url(path);
        let mut request = self.client.delete(&url);
        
        request = request.headers(self.default_headers.clone());
        
        if let Some(headers) = headers {
            for (key, value) in headers {
                let header_name = HeaderName::from_bytes(key.as_bytes())
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header name: {}", key)))?;
                let header_value = HeaderValue::from_str(&value)
                    .map_err(|_| HttpError::InvalidHeader(format!("Invalid header value: {}", value)))?;
                request = request.header(header_name, header_value);
            }
        }
        
        let response = request.send()?;
        self.handle_response(response)
    }
    
    /// 处理响应
    fn handle_response(&self, response: Response) -> HttpResult<String> {
        let status = response.status();
        
        if status.is_success() {
            Ok(response.text()?)
        } else {
            let body = response.text().unwrap_or_else(|_| "Failed to read response body".to_string());
            Err(HttpError::HttpError {
                status: status.as_u16(),
                body,
            })
        }
    }
}

/// 下载文件
/// 
/// # Examples
/// ```
/// use librarys::network::download_file;
/// 
/// download_file("https://httpbin.org/json", "./output.json").unwrap();
/// ```
pub fn download_file(url: &str, output_path: &str) -> HttpResult<()> {
    use std::fs::File;
    use std::io::copy;
    
    let client = Client::new();
    let response = client.get(url).send()?;
    
    if !response.status().is_success() {
        let status = response.status().as_u16();
        let body = response.text().unwrap_or_else(|_| "Failed to read response body".to_string());
        return Err(HttpError::HttpError {
            status,
            body,
        });
    }
    
    let mut output_file = File::create(output_path)
        .map_err(|e| HttpError::InvalidUrl(format!("Failed to create file: {}", e)))?;
    
    let mut response = response; // 可变引用
    copy(&mut response, &mut output_file)
        .map_err(|e| HttpError::InvalidUrl(format!("Failed to write file: {}", e)))?;
    
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;

    #[test]
    fn test_http_client_creation() {
        let client = HttpClient::new();
        assert!(client.base_url.is_none());
        assert_eq!(client.timeout, Duration::from_secs(30));
    }

    #[test]
    fn test_http_client_with_base_url() {
        let client = HttpClient::new().with_base_url("https://api.example.com");
        assert_eq!(client.base_url, Some("https://api.example.com".to_string()));
    }

    #[test]
    fn test_http_client_with_header() {
        let client = HttpClient::new()
            .with_header("Authorization", "Bearer token123")
            .unwrap();
        
        assert!(client.default_headers.contains_key("authorization"));
    }

    #[test]
    fn test_build_url() {
        let client = HttpClient::new().with_base_url("https://api.example.com");
        
        assert_eq!(client.build_url("/users"), "https://api.example.com/users");
        assert_eq!(client.build_url("users"), "https://api.example.com/users");
        assert_eq!(client.build_url("https://other.com/api"), "https://other.com/api");
    }

    // 注意：以下测试需要网络连接，在CI/CD环境中可能需要禁用
    #[test]
    #[ignore] // 使用 cargo test -- --ignored 来运行
    fn test_http_get_real() {
        let result = http_get("https://httpbin.org/get");
        assert!(result.is_ok());
        
        let response = result.unwrap();
        assert!(response.contains("httpbin.org"));
    }

    #[test]
    #[ignore]
    fn test_http_post_real() {
        let data = r#"{"test": "data"}"#;
        let result = http_post("https://httpbin.org/post", data);
        assert!(result.is_ok());
        
        let response = result.unwrap();
        assert!(response.contains("test"));
    }

    #[test]
    #[ignore]
    fn test_http_client_post_json() {
        let client = HttpClient::new();
        let json_data = json!({
            "name": "test",
            "value": 123
        });
        
        let result = client.post_json("https://httpbin.org/post", &json_data, None);
        assert!(result.is_ok());
    }
}